import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

export class StatsTracker {
    constructor() {
        this.statsFile = path.join(__dirname, '../data/user-stats.json');
        this.stats = {};
        this.intervalStats = {}; // 5-minute interval stats
        this.loadStats();
        
        // Clear old interval data every 5 minutes
        setInterval(() => this.rotateIntervalStats(), 5 * 60 * 1000);
    }

    async loadStats() {
        try {
            const data = await fs.readFile(this.statsFile, 'utf8');
            const parsed = JSON.parse(data);
            this.stats = parsed.allTime || {};
            this.intervalStats = parsed.intervals || {};
        } catch (error) {
            // Initialize if file doesn't exist
            this.stats = {};
            this.intervalStats = {};
            await this.saveStats();
        }
    }

    async saveStats() {
        try {
            const dir = path.dirname(this.statsFile);
            await fs.mkdir(dir, { recursive: true });
            
            const data = {
                allTime: this.stats,
                intervals: this.intervalStats,
                lastUpdated: new Date().toISOString()
            };
            
            await fs.writeFile(this.statsFile, JSON.stringify(data, null, 2));
        } catch (error) {
            console.error('Error saving stats:', error);
        }
    }

    getCurrentInterval() {
        const now = new Date();
        const minutes = Math.floor(now.getMinutes() / 5) * 5;
        now.setMinutes(minutes, 0, 0);
        return now.toISOString();
    }

    async trackRequest(username, requestData) {
        const {
            success = true,
            duration = 0,
            requestSize = 0,
            responseSize = 0,
            statusCode = 200,
            endpoint = '',
            error = null
        } = requestData;

        const interval = this.getCurrentInterval();
        
        // Initialize user stats if needed
        if (!this.stats[username]) {
            this.stats[username] = {
                totalRequests: 0,
                successfulRequests: 0,
                failedRequests: 0,
                totalDuration: 0,
                totalRequestSize: 0,
                totalResponseSize: 0,
                averageDuration: 0,
                successRate: 0,
                endpoints: {},
                errors: []
            };
        }

        // Initialize interval stats if needed
        if (!this.intervalStats[interval]) {
            this.intervalStats[interval] = {};
        }
        
        if (!this.intervalStats[interval][username]) {
            this.intervalStats[interval][username] = {
                requests: 0,
                successful: 0,
                failed: 0,
                totalDuration: 0,
                totalSize: 0,
                errors: 0
            };
        }

        // Update all-time stats
        const userStats = this.stats[username];
        userStats.totalRequests++;
        
        if (success) {
            userStats.successfulRequests++;
        } else {
            userStats.failedRequests++;
            if (error) {
                userStats.errors.push({
                    timestamp: new Date().toISOString(),
                    error: error,
                    endpoint: endpoint,
                    statusCode: statusCode
                });
                // Keep only last 100 errors
                if (userStats.errors.length > 100) {
                    userStats.errors = userStats.errors.slice(-100);
                }
            }
        }
        
        userStats.totalDuration += duration;
        userStats.totalRequestSize += requestSize;
        userStats.totalResponseSize += responseSize;
        userStats.averageDuration = userStats.totalDuration / userStats.totalRequests;
        userStats.successRate = (userStats.successfulRequests / userStats.totalRequests) * 100;
        
        // Track endpoint usage
        if (!userStats.endpoints[endpoint]) {
            userStats.endpoints[endpoint] = 0;
        }
        userStats.endpoints[endpoint]++;

        // Update interval stats
        const intervalUserStats = this.intervalStats[interval][username];
        intervalUserStats.requests++;
        if (success) {
            intervalUserStats.successful++;
        } else {
            intervalUserStats.failed++;
            intervalUserStats.errors++;
        }
        intervalUserStats.totalDuration += duration;
        intervalUserStats.totalSize += requestSize + responseSize;

        // Save stats periodically (every 10 requests)
        if (userStats.totalRequests % 10 === 0) {
            await this.saveStats();
        }
    }

    rotateIntervalStats() {
        // Keep only last 24 hours of interval data (288 intervals)
        const intervals = Object.keys(this.intervalStats).sort();
        if (intervals.length > 288) {
            const toRemove = intervals.slice(0, intervals.length - 288);
            toRemove.forEach(interval => {
                delete this.intervalStats[interval];
            });
        }
        this.saveStats();
    }

    getStats(username = null) {
        if (username) {
            return this.stats[username] || null;
        }
        return this.stats;
    }

    getIntervalStats(interval = null) {
        if (interval) {
            return this.intervalStats[interval] || {};
        }
        return this.intervalStats;
    }

    getTopUsers(metric = 'requests', limit = 10, interval = null) {
        let data;
        
        if (interval) {
            data = this.intervalStats[interval] || {};
        } else {
            // Get current interval
            data = this.intervalStats[this.getCurrentInterval()] || {};
        }

        const users = Object.entries(data).map(([username, stats]) => {
            let value;
            switch (metric) {
                case 'requests':
                    value = stats.requests || 0;
                    break;
                case 'duration':
                    value = stats.totalDuration || 0;
                    break;
                case 'size':
                    value = stats.totalSize || 0;
                    break;
                case 'errors':
                    value = stats.errors || 0;
                    break;
                default:
                    value = 0;
            }
            
            return { username, value, stats };
        });

        users.sort((a, b) => b.value - a.value);
        return users.slice(0, limit);
    }

    getHistoricalData(intervals = 12) {
        const sortedIntervals = Object.keys(this.intervalStats).sort().slice(-intervals);
        
        const data = {
            intervals: sortedIntervals,
            requestCounts: {},
            durations: {},
            sizes: {},
            failureRates: []
        };

        sortedIntervals.forEach(interval => {
            const intervalData = this.intervalStats[interval] || {};
            
            // Aggregate data for this interval
            let totalRequests = 0;
            let totalFailed = 0;
            
            Object.entries(intervalData).forEach(([username, stats]) => {
                if (!data.requestCounts[username]) {
                    data.requestCounts[username] = [];
                    data.durations[username] = [];
                    data.sizes[username] = [];
                }
                
                data.requestCounts[username].push(stats.requests || 0);
                data.durations[username].push(stats.totalDuration || 0);
                data.sizes[username].push(stats.totalSize || 0);
                
                totalRequests += stats.requests || 0;
                totalFailed += stats.failed || 0;
            });
            
            // Calculate failure rate for this interval
            const failureRate = totalRequests > 0 ? (totalFailed / totalRequests) * 100 : 0;
            data.failureRates.push(failureRate);
        });

        return data;
    }

    getSummaryStats() {
        const summary = {
            totalUsers: Object.keys(this.stats).length,
            totalRequests: 0,
            totalSuccess: 0,
            totalFailures: 0,
            overallSuccessRate: 0,
            averageDuration: 0,
            totalDataTransferred: 0
        };

        Object.values(this.stats).forEach(userStats => {
            summary.totalRequests += userStats.totalRequests || 0;
            summary.totalSuccess += userStats.successfulRequests || 0;
            summary.totalFailures += userStats.failedRequests || 0;
            summary.averageDuration += userStats.totalDuration || 0;
            summary.totalDataTransferred += (userStats.totalRequestSize || 0) + (userStats.totalResponseSize || 0);
        });

        if (summary.totalRequests > 0) {
            summary.overallSuccessRate = (summary.totalSuccess / summary.totalRequests) * 100;
            summary.averageDuration = summary.averageDuration / summary.totalRequests;
        }

        return summary;
    }
}

export default StatsTracker;